using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace URP.WarFog
{
    public class CountyArea
    {
        public int Id;
        public bool FogClear;
        public bool Finish;
        private float value;
        private const int limit = 20;
        private static Queue<CountyArea> pool = new Queue<CountyArea>(10);

        public void SetState(bool clear)
        {
            FogClear = clear;
            Finish = false;
            value = clear ? 0 : 1;
        }

        public bool UpdateArea(float step)
        {
            if (FogClear)
            {
                value += step;
                Finish = value >= 1;
            }
            else
            {
                value -= step;
                Finish = value <= 0;
            }
            return Finish;
        }
        public static CountyArea GetInstance()
        {
            if (pool.Count > 0)
            {
                return pool.Dequeue();
            }
            return new CountyArea();
        }

        public static void ReturnInstance(CountyArea insatnce)
        {
            if (pool.Count < limit)
            {
                pool.Enqueue(insatnce);
            }
        }

        public static void Clear()
        {
            pool.Clear();
        }

    }
    public class WarFog
    {

        public float _step = 0.01f;
        private List<CountyArea> unlockIds = new List<CountyArea>();
        private Vector4[] datas;



        public void InitFog(Vector4[] datas)
        {
            this.datas = datas;
        }

        public void ClearWarFog()
        {
            unlockIds.Clear();
            datas = null;
            CountyArea.Clear();
        }

        public bool UpdateWarFog(CommandBuffer buffer)
        {

            var dirty = CheckIfCountyListDirty(buffer);
            return dirty;
        }

        public void SetFogStep(float step)
        {
            this._step = step;
        }

        public void FogClear(int[] ids)
        {
            for (var index = 0; index < ids.Length; index++)
            {
                var id = ids[index];
                SetFogState(id, true);
            }
        }

        public void FogAppear(int[] ids)
        {
            for (var index = 0; index < ids.Length; index++)
            {
                var id = ids[index];
                SetFogState(id, false);
            }
        }

        public void Reset()
        {
            ReturnAllArea();
            for (var index = 0; index < datas.Length; index++)
            {
                var uv = datas[index];
                datas[index] = EncodeFogInfo(uv, false);
            }
            lastCount = -1;
        }

        public void SetFogState(int id, bool fogClear)
        {
            var exsit = unlockIds.Find(item => item.Id == id);
            if (exsit == null)
            {
                var area = CountyArea.GetInstance();
                area.Id = id;
                area.SetState(fogClear);
                unlockIds.Add(area);
            }
            else
            {
                if (fogClear != exsit.FogClear)
                {
                    exsit.SetState(fogClear);
                }
            }
        }

        private int lastCount = -1;
        private bool CheckIfCountyListDirty(CommandBuffer buffer)
        {
            var current = unlockIds.Count;
            var dirty = false;
            for (var i = current - 1; i >= 0; i--)
            {
                var area = unlockIds[i];
                var id = area.Id;
                var fogClear = area.FogClear;
                var uv = datas[id];
                var lastIsFogClear = IsFogClear(uv);
                if (lastIsFogClear != fogClear)
                {
                    datas[id] = EncodeFogInfo(uv, fogClear);
                    dirty = true;
                }
                if (area.UpdateArea(_step))
                {
                    CountyArea.ReturnInstance(area);
                    unlockIds.RemoveAt(i);
                }
            }

            dirty |= unlockIds.Count != lastCount;
            buffer.SetGlobalFloat("_Step", _step);
            if (dirty)
            {
                buffer.SetGlobalVectorArray("uvs", datas);
                lastCount = unlockIds.Count;
            }
            return dirty || lastCount != 0;
        }


        private static Vector4 EncodeId(Vector4 v, int id)
        {
            var x = v.x;
            x += id << 1;
            v.x = x;
            return v;
        }

        private static Vector4 EncodeFogInfo(Vector4 v, bool fogOn)
        {
            var y = v.y;
            if (fogOn)
            {
                if (y < 2)
                {
                    y += 2;
                }
            }
            else
            {
                if (y >= 2)
                {
                    y -= 2;
                }
            }
            v.y = y;
            return v;
        }
        private static bool IsFogClear(Vector4 v)
        {
            return v.y >= 2;
        }

        private void ReturnAllArea()
        {
            for (var index = 0; index < unlockIds.Count; index++)
            {
                CountyArea.ReturnInstance(unlockIds[index]);
            }
            unlockIds.Clear();
        }
    }
}